﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace LogikBug.Async.Collections
{
	public class ConcurrentList<T> : IProducerConsumerCollection<T>, ICollection<T>
	{
		#region Fields

		private readonly object _syncRoot = new object();
		private readonly List<T> _items = new List<T>();

		#endregion

		#region Properties

		///<summary>
		/// Gets the <typeparamref name="T"/> object at the given index.
		///</summary>
		///<param name="index">The index of the item.</param>
		public T this[int index]
		{
			get
			{
				lock (_syncRoot)
				{
					return _items[index];
				}
			}
			set
			{
				lock (_syncRoot)
				{
					_items[index] = value;
				}
			}
		}

		public int Count
		{
			get
			{
				return _items.Count;
			}
		}

		public bool IsReadOnly
		{
			get
			{
				return false;
			}
		}

		public bool IsSynchronized
		{
			get
			{
				return true;
			}
		}

		public object SyncRoot
		{
			get
			{
				return _syncRoot;
			}
		}

		#endregion

		#region Methods

		public virtual void Add(T item)
		{
			lock (_syncRoot)
			{
				_items.Add(item);
			}
		}

		public void Clear()
		{
			lock (_syncRoot)
			{
				_items.Clear();
			}
		}

		public bool Contains(T item)
		{
			lock (_syncRoot)
			{
				return _items.Contains(item);
			}
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			lock (_syncRoot)
			{
				_items.CopyTo(array, arrayIndex);
			}
		}

		public virtual bool Remove(T item)
		{
			lock (_syncRoot)
			{
				return _items.Remove(item);
			}
		}

		public T[] ToArray()
		{
			lock (_syncRoot)
			{
				return _items.ToArray();
			}
		}

		public bool TryAdd(T item)
		{
			Add(item);
			return true;
		}

		public bool TryTake(out T item)
		{
			lock (_syncRoot)
			{
				if (_items.Count > 0)
				{
					item = _items[_items.Count - 1];
					return _items.Remove(item);
				}
			}

			item = default(T);
			return false;
		}

		public bool TryRemove(T item)
		{
			return Remove(item);
		}

		public IEnumerator<T> GetEnumerator()
		{
			lock (_syncRoot)
			{
				return _items.GetEnumerator();
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		void ICollection.CopyTo(Array array, int index)
		{
			Array.Copy(ToArray(), array, index);
		}

		#endregion
	}
}
